(function ($) {
    $.fn.selectChain = function (options) {
        var defaults = {
			url:"#",
            key: "id",
            value: "label",
			emptyData: []
        };
        /*
         * settings parameters:
         * [target] to be the result option container
         * [key,value] used to result to option mapping
         * [url,data,type] used for ajax retieve result
         * [datas,dataKey] used for direct retrieve result
         */
        var settings = $.extend({}, defaults, options);
        
        if (!(settings.target instanceof $)) settings.target = $(settings.target);
        
        return this.each(function () {
            var $$ = $(this);
            
            $$.change(function () {
				var val = $(this).val();
                var data = null;
                if (typeof settings.data == 'string') {
                    data = settings.data + '&' + this.name + '=' + $$.val();
                } else if (typeof settings.data == 'object') {
                    data = settings.data;
                    data[this.name] = val;
                }
                
                settings.target.empty();
                
				var dataBinding = function (j) {
					var options = [], i = 0, o = null;
					if (undefined != j && j && j.length > 0) {
						for (i = 0; i < j.length; i++) {
							// required to get around IE bug (http://support.microsoft.com/?scid=kb%3Ben-us%3B276228)
							o = document.createElement("OPTION");
							o.value = typeof j[i] == 'object' ? j[i][settings.key] : j[i];
							o.text = typeof j[i] == 'object' ? j[i][settings.value] : j[i];
							settings.target.get(0).options[i] = o;
						}
					}else{
						var temp = settings.emptyData;
						for (i = 0; i < temp.length; i++) {
							// required to get around IE bug (http://support.microsoft.com/?scid=kb%3Ben-us%3B276228)
							o = document.createElement("OPTION");
							o.value = typeof temp[i] == 'object' ? temp[i][settings.key] : temp[i];
							o.text = typeof temp[i] == 'object' ? temp[i][settings.value] : temp[i];
							settings.target.get(0).options[i] = o;
						}
					}
					// hand control back to browser for a moment
					setTimeout(function () {
						settings.target
							.find('option:first')
							.attr('selected', 'selected')
							.parent('select')
							.trigger('change');
					}, 0);
				}
				
				var queryError = function (xhr, desc, er) {
					var temp = settings.emptyData, o=null;
					for (i = 0; i < temp.length; i++) {
						// required to get around IE bug (http://support.microsoft.com/?scid=kb%3Ben-us%3B276228)
						o = document.createElement("OPTION");
						o.value = typeof temp[i] == 'object' ? temp[i][settings.key] : temp[i];
						o.text = typeof temp[i] == 'object' ? temp[i][settings.value] : temp[i];
						settings.target.get(0).options[i] = o;
					}
					// hand control back to browser for a moment
					setTimeout(function () {
						settings.target
							.find('option:first')
							.attr('selected', 'selected')
							.parent('select')
							.trigger('change');
					}, 0);
				}
				
				if(settings.datas && undefined != settings.datas[val]){
					var results = settings.datas[val];
					dataBinding(results);
				}else{
					//ajax query data
					$.ajax({
						url: settings.url,
						data: data,
						type: (settings.type || 'get'),
						dataType: 'json',
						success: dataBinding,
						error: queryError
					});
				}
			});
		});
	};
})(jQuery);			
